#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Weazel.Gezel.Model
{
  /// <summary>
  /// Signals are the back bone of the digital logic 
  /// simulator. Everything from expressions, communication
  /// through ports and registers relies on underlying signals.
  /// 
  /// A signal can be assigned during a given cycle and the 
  /// result will be immediately visible. A signal must have
  /// exactly one driver in any simulation cycle which it is
  /// read from.
  /// 
  /// Signals can be directly declared at the datapath and
  /// signalflowgraph levels.
  /// </summary>
  public partial class Signal : AbstractEntity<CommonEntity>, ITypedEntity, ISignalEntity
  {
    /// <summary>
    /// The bitwidth of the signal.
    /// </summary>
    private readonly int width;
    public int Width
    {
      get
      {
        return width;
      }
    }

    /// <summary>
    /// True iff the signal is read as a
    /// two's complement integer.
    /// </summary>
    private readonly bool signed;
    public bool Signed
    {
      get
      {
        return signed;
      }
    }

    /// <summary>
    /// For testing and verificaton purposes a signal
    /// can be driven by external stimuli, if so, the
    /// driver object stores a reference to the stimuli.
    /// </summary>
    private Stimulus driver = null;
    public Stimulus Driver
    {
      get
      {
        return driver;
      }
      set
      {
        driver = value;
      }
    }

    /// <summary>
    /// If the signal is connected to an outport of a
    /// nested datapath, this field stores a reference
    /// to the outport instance.
    /// </summary>
    private OutPort outportDriver = null;
    public OutPort OutportDriver
    {
      get
      {
        return outportDriver;
      }
      internal set
      {
        outportDriver = value;
      }
    }

    /// <summary>
    /// The list of expressions which can drive
    /// this entity during simulation. The
    /// list is not populated before the
    /// verification has completed.
    /// </summary>
    private List<Expression> definers;
    public List<Expression> Definers
    {
      get
      {
        return definers;
      }
    }

    /// <summary>
    /// Maps each definer of this entity to the signalflowgraph
    /// in which the definer is active.
    /// </summary>
    private Dictionary<Expression, SignalFlowGraph> definingSignalFlowGraphs;
    public Dictionary<Expression, SignalFlowGraph> DefiningSignalFlowGraphs
    {
      get
      {
        return definingSignalFlowGraphs;
      }
    }

		protected Signal(CommonEntity parent)
			: base(parent, null)
		{
			this.width = 0;
			this.signed = false;
			this.definers = new List<Expression>();
			this.definingSignalFlowGraphs = new Dictionary<Expression, SignalFlowGraph>();
		}

    /// <summary>
    /// Constructs a new signal with the specified parent, local name
    /// and signal specification.
    /// </summary>
    /// <param name="parent">the parent of the signal</param>
    /// <param name="name">local name</param>
    /// <param name="width">bitwidth</param>
    /// <param name="signed">true iff the contents are signed</param>
    public Signal(CommonEntity parent, string name, int width, bool signed) : base(parent, name)
    {
      this.width = width;
      this.signed = signed;
      this.definers = new List<Expression>();
      this.definingSignalFlowGraphs = new Dictionary<Expression, SignalFlowGraph>();
    }

    /// <summary>
    /// Constructs a new signal with the specified parent, local name, signal 
    /// specification and source code position.
    /// </summary>
    /// <param name="parent">the parent of the signal</param>
    /// <param name="name">local name</param>
    /// <param name="width">bitwidth</param>
    /// <param name="signed">true iff the content is signed</param>
    /// <param name="position">position of this signal in source file</param>
		public Signal(
			CommonEntity parent, 
			string name, 
			int width, 
			bool signed,
			Position startPosition,
			Position endPosition
		)
			: base(parent, name, startPosition, endPosition)
    {
      this.width = width;
      this.signed = signed;
      this.definers = new List<Expression>();
      this.definingSignalFlowGraphs = new Dictionary<Expression, SignalFlowGraph>();
    }

    public Signal Clone(CommonEntity newParent)
    {
      return new Signal(newParent, localName, Width, Signed, startPosition, endPosition);
    }
  }
}
